#pragma once

#include "../Main/Standard.h"
#include "../Utility/Utility.h"
#include "../Container/Dictionary.h"
#include "../Container/DynamicArray.h"

#include "KeyboardData.h"
#include "MouseData.h"

////////////////////////////////////////////////////////////////////////////////////////////////////
/// <Summary>	InputSystem  </Summary>
/// 
/// <purpose>	Engine system used to contain and control input	</purpose>
////////////////////////////////////////////////////////////////////////////////////////////////////

class InputSystem
{
	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Defines an alias representing the keyboard map </Summary>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	typedef Dictionary<unsigned short /*keycode*/, KeyboardData> KeyboardMap;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Defines an alias representing the mouse map </Summary>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	typedef Dictionary<unsigned short /*keycode*/, MouseData> MouseMap;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Defines an alias representing list of keys </Summary>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	typedef DynamicArray<unsigned short> KeyList;

	/// <Summary> The key map that holds all keyboard events</Summary>
	KeyboardMap keyMap;

	/// <Summary> The mouse map that holds all mouse events </Summary>
	MouseMap mouseMap;

	/// <Summary> The list of changes that occured this frame </Summary>
	KeyList keyChanges;

private:

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Makes copy and assignment unavailable to this class </Summary>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	DISALLOW_COPY_AND_ASSIGN(InputSystem)

	InputSystem() : keyMap(Utility::HashFuncUShort), mouseMap(Utility::HashFuncUShort) { }
	~InputSystem() { }

	/// <Summary> The instance of this class </Summary>
	static InputSystem* instance;

public:

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Gets the instance of this class </Summary>
	///
	/// <Return>	The instance of this class </Return>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	static InputSystem& GetInstance();

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Deletes the instance of this class </Summary>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	static void DeleteInstance();

private:

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Process the keyboard event described by rawKeyboard </Summary>
	///
	/// <Param name="rawKeyboard">	The raw keyboard </Param>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	void ProcessKeyboardEvent(const RAWKEYBOARD &rawKeyboard);

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Process the mouse event described by rawMouse </Summary>
	///
	/// <Param name="rawMouse">	The raw mouse </Param>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	void ProcessMouseEvent(const RAWMOUSE &rawMouse);

public:
	

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Initializes the input manager to accept input events </Summary>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	void Initialize();

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Shuts down the input manager </Summary>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	void Shutdown();

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Updates the input manager with a key define by the windows LPARAM </Summary>
	///
	/// <Param name="lParam">	The lParam field of the message </Param>
	/// 
	/// <Remarks> 
	///		This function should be called inside the windows message loop 
	///		whenever a WM_INPUT message is recieved
	///	</Remarks>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	void Update(LPARAM lParam);

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Update that is run every frame of the game </Summary>
	/// 
	/// <Remarks>	
	/// 	This function should be called at the END of every game update
	/// 	for key presses to be accurately documented
	/// </Remarks>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	void FrameUpdate();

public:

	bool CheckForController();

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Key down event for the keyboard </Summary>
	///
	/// <Param name="key">	The key </Param>
	///
	/// <Return>	True if the keyboard event is down, false if it is not </Return>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	bool KeyDown(unsigned short key);

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Key up event for the keyboard </Summary>
	///
	/// <Param name="key">	The key </Param>
	///
	/// <Return>	True if the keyboard event is up, false if it is not </Return>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	bool KeyUp(unsigned short key);

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Key pressed event for the keyboard </Summary>
	///
	/// <Param name="key">	The key </Param>
	///
	/// <Return>	
	/// 	True if the keyboard event has been pressed this frame, false if it has not
	/// </Return>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	bool KeyPressed(unsigned short key);

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Key released event for the keyboard </Summary>
	///
	/// <Param name="key">	The key </Param>
	///
	/// <Return>	
	/// 	True if the keyboard event has been released this frame, false if it has not
	/// </Return>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	bool KeyReleased(unsigned short key);

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Key down event for the mouse </Summary>
	///
	/// <Param name="key">	The key. </Param>
	///
	/// <Return>	true if it succeeds, false if it fails. </Return>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	bool MouseDown(unsigned short key);

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Key up event for the mouse </Summary>
	///
	/// <Param name="key">	The key. </Param>
	///
	/// <Return>	true if it succeeds, false if it fails. </Return>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	bool MouseUp(unsigned short key);

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Key pressed event for the mouse </Summary>
	///
	/// <Param name="key">	The key. </Param>
	///
	/// <Return>	true if it succeeds, false if it fails. </Return>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	bool MousePressed(unsigned short key);

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Key released event for the mouse </Summary>
	///
	/// <Param name="key">	The key. </Param>
	///
	/// <Return>	true if it succeeds, false if it fails. </Return>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	bool MouseReleased(unsigned short key);

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Gets the cursor position </Summary>
	///
	/// <Return>	The cursor position </Return>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	POINT GetCursorPos();

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Gets the cursor position. </Summary>
	///
	/// <Param name="ref">	the POINT to be written to </Param>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	void GetCursorPos(POINT& ref);
};